#pragma once
#include <iostream>
#include <mutex>

template<class T>
struct Delete
{
    void operator()(T* ptr)
    {
        delete ptr;
    }
};


template<class T, class D = Delete<T>>
class shared_ptr
{
public:
    shared_ptr(T* ptr = nullptr, D del = D())
    :_ptr(ptr), _pcount(new int(1)), _pmtx(new pthread_mutex_t), _del(del)
    {
        pthread_mutex_init(_pmtx, nullptr);  // 初始化互斥锁
        std::cout << "shared_ptr" << std::endl;
    }

    // 析构时释放资源
    ~shared_ptr()
    {
        bool flag = false;
        pthread_mutex_lock(_pmtx);
        if((*_pcount)-- == 1)
        {
            if(_ptr != nullptr)
            {
                _del(_ptr);
                _ptr = nullptr;
            }
            delete _pcount;
            flag = true;
        }
        pthread_mutex_unlock(_pmtx);
        if(flag)
        {
            pthread_mutex_destroy(_pmtx);
            delete _pmtx;
        }

        std::cout << " ~shared_ptr" << std::endl;
    }

    T& operator*()
    {
        return *_ptr;
    }

    T* operator->()
    {
        return _ptr;
    }

    T*& get()
    {
        return _ptr;
    }

    int UseCnt()
    {
        return *_pcount;
    }

    // 赋值，资源只能被一个shared_ptr指向，p2 = p1
    shared_ptr<T>& operator=(shared_ptr<T>& p1)
    {
        if(this != &p1)
        {
            std::cout << "operator=" << std::endl;
            bool flag = false;
            pthread_mutex_lock(_pmtx);
            if((*_pcount)-- == 1)
            {
                if(_ptr != nullptr)
                {
                    _del(_ptr);
                    _ptr = nullptr;
                }
                delete _pcount;
                flag = true;
            }
            pthread_mutex_unlock(_pmtx);
            if(flag)
            {
                pthread_mutex_destroy(_pmtx);
                delete _pmtx;
            }
            // p1计数增加
            *(p1._pcount) += 1;
            // ptr指向p1资源
            _ptr = p1._ptr;
            _pcount = p1._pcount;
            _pmtx = p1._pmtx;
        }

        return *this;
    }

    // 拷贝构造p2(p1)
    shared_ptr(shared_ptr<T>& p1)
    :_ptr(p1._ptr), _pcount(p1._pcount), _pmtx(p1._pmtx)
    {
        pthread_mutex_lock(_pmtx);
        std::cout << "shared_ptr(shared_ptr<T>& p1)" << std::endl;
        // p1计数增加
        *(p1._pcount) += 1;
        // ptr指向p1资源
        pthread_mutex_unlock(_pmtx);
    }

private:
    T* _ptr; // 指针
    int* _pcount; // 资源计数
    pthread_mutex_t* _pmtx; // 互斥锁
    D _del; // 删除器
};